package com.yand.redis;


import redis.clients.jedis.Jedis;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * 漏斗限流的实现
 */
public class FunnelRateLimiter {

    static class Funnel{
       int capacity;
       float leakingRate;
       int leftQuota;
       long leakingTs;

       public Funnel(int capacity, float leakingRate){
           this.capacity    = capacity;
           this.leakingRate = leakingRate;
           this.leftQuota   = capacity;
           this.leakingTs   = System.currentTimeMillis();
       }

       void makeSpace(){
           long nowTs =  System.currentTimeMillis();
           long deltaTs = nowTs - leakingTs;
           int deltaQuota = (int)(deltaTs* leakingRate);
           if(deltaQuota < 0){
               this.leftQuota = capacity;
               this.leakingTs = nowTs;
               return ;
           }

           if(deltaQuota < 1){
               return ;
           }

           this.leftQuota += deltaQuota;
           this.leakingTs = nowTs;
           if(this.leftQuota > this.capacity){
               this.leftQuota = this.capacity;
           }
       }

       boolean watering(int quota){
           makeSpace();
           if(this.leftQuota >= quota){

               this.leftQuota -= quota;

               return true;
           }

           return  false;
       }
    }

    private Map<String, Funnel>  funnels = new HashMap<>();


    /**
     * 漏斗限流算法的实现
     * @param userId
     * @param actionKey
     * @param capacity
     * @param leakingRate
     * @return
     */
    public boolean isActionAllowed(String userId, String actionKey, int capacity, float leakingRate){
        String key = String.format("%s:%s", userId, actionKey);
        Funnel funnel = funnels.get(key);

        if(funnel == null){
            funnel = new Funnel(capacity, leakingRate);
            funnels.put(key, funnel);
        }

        return funnel.watering(1);
    }


    public static void main(String [] args){
        Jedis jedis =  RedisUtil.getJedis();
        FunnelRateLimiter simpleRateLimter = new FunnelRateLimiter();
        for(int i  =0 ; i < 20; i ++){
            try {
                System.out.println(simpleRateLimter.isActionAllowed("yand","reply", 5,1));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }


}
